home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / write.c < prev    next >
Text File  |  1995-05-02  |  48KB  |  1,708 lines

  1. /* Xconq game module writing.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. #include "conq.h"
  11. extern int gamestatesafe;
  12.  
  13. #define key(x) (keyword_name(x))
  14.  
  15. extern char *escaped_symbol PROTO ((char *str));
  16. extern char *escaped_string PROTO ((char *str));
  17.  
  18. static void start_form PROTO ((char *hd));
  19. static void add_to_form PROTO ((char *x));
  20. static void add_num_to_form PROTO ((int x));
  21. static void end_form PROTO ((void));
  22. static void newline_form PROTO ((void));
  23. static void space_form PROTO ((void));
  24. static void write_bool_prop PROTO ((char *name, int value, int dflt, int nodefaulting, int addnewline));
  25. static void write_num_prop PROTO ((char *name, int value, int dflt, int nodefaulting, int addnewline));
  26. static void write_str_prop PROTO ((char *name, char *value, char *dflt, int nodefaulting, int addnewline));
  27. static int string_not_default PROTO ((char *str, char *dflt));
  28. static void write_lisp_prop PROTO ((char *name, struct a_obj *value, struct a_obj *dflt, int nodefaulting, int ascdr, int addnewline));
  29. static void write_utype_value_list PROTO ((char *name, short *arr, int dflt, int addnewline));
  30. static void write_mtype_value_list PROTO ((char *name, short *arr, int dflt, int addnewline));
  31. static void write_side_value_list PROTO ((char *name, short *arr, int dflt, int addnewline));
  32. static void write_utype_string_list PROTO ((char *name, char **arr , char *dflt, int addnewline));
  33. extern char *shortest_escaped_name PROTO ((int u));
  34. static void write_types PROTO ((void));
  35. static void write_tables PROTO ((void));
  36. static void write_type_name_list PROTO ((int typ, int *flags, int dim));
  37. #if 0
  38. static void write_type_value_list PROTO ((int typ, int *flags, int dim, int (*getter)(int, int), int i));
  39. #endif
  40. static void write_table PROTO ((char *name, int (*getter)(int, int), int dflt, int typ1, int typ2));
  41. static void write_world PROTO ((void));
  42. static void write_areas PROTO ((Module *module));
  43. static void write_area_terrain PROTO ((int compress));
  44. static void write_area_aux_terrain PROTO ((int compress));
  45. static void write_area_features PROTO ((int compress));
  46. static void write_area_elevations PROTO ((int compress));
  47. static void write_area_people_sides PROTO ((int compress));
  48. static void write_area_materials PROTO ((int compress));
  49. static void write_area_temperatures PROTO ((int compress));
  50. static void write_area_clouds PROTO ((int compress));
  51. static void write_area_winds PROTO ((int compress));
  52. static void write_globals PROTO ((void));
  53. static void write_scorekeepers PROTO ((void));
  54. static void write_sides PROTO ((Module *module));
  55. static void write_side_properties PROTO ((Side *side));
  56. static int fn_terrain_view PROTO ((int x, int y));
  57. static int fn_unit_view PROTO ((int x, int y));
  58. static int fn_unit_view_date PROTO ((int x, int y));
  59. static void write_side_view PROTO ((Side *side, int compress));
  60. static void write_players PROTO ((void));
  61. static void write_player PROTO ((struct a_player *player));
  62. static void write_units PROTO ((Module *module));
  63. static void write_unit_properties PROTO ((Unit *unit));
  64. static void write_unit_act PROTO ((Unit *unit));
  65. static void write_unit_plan PROTO ((Unit *unit));
  66. static void write_task PROTO ((Task *task));
  67. static void write_goal PROTO ((Goal *goal, int keyword));
  68. static void write_rle PROTO ((int (*datafn)(int, int), int lo, int hi, int (*translator)(int), int compress));
  69. static void write_run PROTO ((int run, int val));
  70. static void write_history PROTO ((void));
  71. static void write_past_unit PROTO ((PastUnit *pastunit));
  72. static void write_historical_event PROTO ((HistEvent *hevt));
  73. static int reshaped_point PROTO ((int x1, int y1, int *x2p, int *y2p));
  74. static int original_point PROTO ((int x1, int y1, int *x2p, int *y2p));
  75.  
  76. /* The pointer to the file being written to. */
  77.  
  78. static FILE *fp;
  79.  
  80. /* True if the area is to be saved to a different size than it is now. */
  81.  
  82. static int doreshape = FALSE;
  83.  
  84. static Module *reshaper = NULL;
  85.  
  86. static char *shortestbuf = NULL;
  87.  
  88. static char *escapedthingbuf = NULL;
  89.  
  90. /* Little routines to do low-level syntax.  While these look excessive, calling fprintf
  91.    directly would result in an object code size increase of as much as 25%. */
  92.  
  93. static void
  94. start_form(hd)
  95. char *hd;
  96. {
  97.     fprintf(fp, "(%s", hd);
  98. }
  99.  
  100. static void
  101. add_to_form(x)
  102. char *x;
  103. {
  104.     fprintf(fp, " %s", x);
  105. }
  106.  
  107. static void
  108. add_num_to_form(x)
  109. int x;
  110. {
  111.     fprintf(fp, " %d", x);
  112. }
  113.  
  114. static void
  115. end_form()
  116. {
  117.     fprintf(fp, ")");
  118. }
  119.  
  120. static void
  121. newline_form()
  122. {
  123.     fprintf(fp, "\n");
  124. }
  125.  
  126. static void
  127. space_form()
  128. {
  129.     fprintf(fp, " ");
  130. }
  131.  
  132. /* These two routines make sure that any symbols and strings can
  133.    be read in again. */
  134.  
  135. char *
  136. escaped_symbol(str)
  137. char *str;
  138. {
  139.     char *tmp = str;
  140.  
  141.     if (str[0] == '|' && str[strlen(str)-1] == '|')
  142.       return str;
  143.     while (*tmp != '\0') {
  144.     if (((char *) strchr(" ()#\";|", *tmp)) != NULL || isdigit(str[0])) {
  145.         sprintf(escapedthingbuf, "|%s|", str);
  146.         return escapedthingbuf;
  147.     }
  148.     ++tmp;
  149.     }
  150.     return str;
  151. }
  152.  
  153. /* Note that this works correctly on NULL strings, turning them into
  154.    strings of length 0. */
  155.  
  156. char *
  157. escaped_string(str)
  158. char *str;
  159. {
  160.     char *tmp = str, *rslt = escapedthingbuf;
  161.  
  162.     *rslt++ = '"';
  163.     if (str != NULL) {
  164.     while (*tmp != 0) {
  165.         if (*tmp == '"') *rslt++ = '\\';
  166.         *rslt++ = *tmp++;
  167.     }
  168.     }
  169.     *rslt++ = '"';
  170.     *rslt = '\0';
  171.     return escapedthingbuf;
  172. }
  173.  
  174. static void
  175. write_bool_prop(name, value, dflt, nodefaulting, addnewline)
  176. char *name;
  177. int value, dflt, nodefaulting, addnewline;
  178. {
  179.     if (nodefaulting || value != dflt) {
  180.     fprintf(fp, " (%s %s)", name, (value ? "true" : "false"));
  181.     if (addnewline) 
  182.       newline_form();
  183.     }
  184. }
  185.  
  186. static void
  187. write_num_prop(name, value, dflt, nodefaulting, addnewline)
  188. char *name;
  189. int value, dflt, nodefaulting, addnewline;
  190. {
  191.     if (nodefaulting || value != dflt) {
  192.         /* Write a normal value or a dice spec, as appropriate. */
  193.     if (value >> 14 == 1) {
  194.         fprintf(fp, " (%s %dd%d+%d)", name,
  195.             (value >> 11) & 0x07, (value >> 7) & 0x0f, value & 0x7f);
  196.     } else {
  197.         fprintf(fp, " (%s %d)", name, value);
  198.     }
  199.     if (addnewline)
  200.       newline_form();
  201.     }
  202. }
  203.  
  204. /* Handle the writing of a single string-valued property. */
  205.  
  206. static void
  207. write_str_prop(name, value, dflt, nodefaulting, addnewline)
  208. char *name, *value, *dflt;
  209. int nodefaulting, addnewline;
  210. {
  211.     if (nodefaulting || string_not_default(value, dflt)) {
  212.     fprintf(fp, " (%s %s)", name, escaped_string(value));
  213.     if (addnewline)
  214.       newline_form();
  215.     }
  216. }
  217.  
  218. static int
  219. string_not_default(str, dflt)
  220. char *str, *dflt;
  221. {
  222.     if (empty_string(dflt)) {
  223.     if (empty_string(str)) {
  224.         return FALSE;
  225.     } else {
  226.         return TRUE;
  227.     }
  228.     } else {
  229.     if (empty_string(str)) {
  230.         return TRUE;
  231.     } else {
  232.         return (strcmp(str, dflt) != 0);
  233.     }
  234.     }
  235. }
  236.  
  237. static void
  238. write_lisp_prop(name, value, dflt, nodefaulting, ascdr, addnewline)
  239. char *name;
  240. Obj *value, *dflt;
  241. int nodefaulting, ascdr, addnewline;
  242. {
  243.     Obj *rest;
  244.  
  245.     if (nodefaulting || !equal(value, dflt)) {
  246.     space_form();
  247.     start_form(name);
  248.     if (ascdr && consp(value)) {
  249.         for (rest = value; rest != lispnil; rest = cdr(rest)) {
  250.             space_form();
  251.             fprintlisp(fp, car(rest));
  252.         }
  253.     } else {
  254.         space_form();
  255.         fprintlisp(fp, value);
  256.     }
  257.     end_form();
  258.     if (addnewline)
  259.       newline_form();
  260.     }
  261. }
  262.  
  263. static void
  264. write_utype_value_list(name, arr, dflt, addnewline)
  265. char *name;
  266. short *arr;
  267. int dflt, addnewline;
  268. {
  269.     int u;
  270.  
  271.     if (arr == NULL)
  272.       return;
  273.     space_form();
  274.     start_form(name);
  275.     for_all_unit_types(u) {
  276.     fprintf(fp, " %hd", arr[u]);
  277.     }
  278.     end_form();
  279.     if (addnewline)
  280.       newline_form();
  281. }
  282.  
  283. static void
  284. write_mtype_value_list(name, arr, dflt, addnewline)
  285. char *name;
  286. short *arr;
  287. int dflt, addnewline;
  288. {
  289.     int m;
  290.  
  291.     if (nummtypes == 0 || arr == NULL)
  292.       return;
  293.     space_form();
  294.     start_form(name);
  295.     for_all_material_types(m) {
  296.     fprintf(fp, " %hd", arr[m]);
  297.     }
  298.     end_form();
  299.     if (addnewline)
  300.       newline_form();
  301. }
  302.  
  303. static void
  304. write_side_value_list(name, arr, dflt, addnewline)
  305. char *name;
  306. short *arr;
  307. int dflt, addnewline;
  308. {
  309.     int s;
  310.  
  311.     if (arr == NULL)
  312.       return;
  313.     space_form();
  314.     start_form(name);
  315.     for (s = 0; s <= numsides; ++s) {
  316.     fprintf(fp, " %hd", arr[s]);
  317.     }
  318.     end_form();
  319.     if (addnewline)
  320.       newline_form();
  321. }
  322.  
  323. static void
  324. write_utype_string_list(name, arr, dflt, addnewline)
  325. char *name;
  326. char **arr, *dflt;
  327. int addnewline;
  328. {
  329.     int u;
  330.  
  331.     if (arr == NULL)
  332.       return;
  333.     space_form();
  334.     start_form(name);
  335.     for_all_unit_types(u) {
  336.     fprintf(fp, " %s", escaped_string(arr[u]));
  337.     }
  338.     end_form();
  339.     if (addnewline)
  340.       newline_form();
  341. }
  342.  
  343. /* Return the shortest properly escaped name that can be used to identify
  344.    unit type. */
  345.  
  346. char *
  347. shortest_escaped_name(u)
  348. int u;
  349. {
  350.     char *typename = u_type_name(u);
  351.  
  352.     if (shortestbuf == NULL)
  353.       shortestbuf = xmalloc(BUFSIZE);
  354.     if (strlen(u_internal_name(u)) < strlen(typename)) {
  355.     typename = u_internal_name(u);
  356.     }
  357.     sprintf(shortestbuf, "%s", escaped_symbol(typename));
  358.     return shortestbuf;
  359. }
  360.  
  361. /* A saved game should include everything necessary to recreate a game
  362.    exactly.  It is important that this routine not attempt to use graphics,
  363.    since it may be called when graphics code fails.  Returns TRUE if
  364.    that save was successful. */
  365.  
  366. int
  367. write_entire_game_state(fname)
  368. char *fname;
  369. {
  370.     Module *module = create_game_module(fname);
  371.     int rslt;
  372.  
  373.     module->filename = fname;
  374.     module->compresslayers = TRUE;
  375.     module->defall = TRUE;
  376.     rslt = write_game_module(module);
  377.     /* Record that the game's state is accurately saved away. */
  378.     if (rslt)
  379.       gamestatesafe = TRUE;
  380.     /* Note in the history that a copy was made. */
  381.     record_event(H_GAME_SAVED, ALLSIDES);
  382.     return rslt;
  383. }
  384.  
  385. /* Given a game module telling what is in the module, write out a file
  386.    containing the requested content.  Return true if everything went OK. */
  387.  
  388. int
  389. write_game_module(module)
  390. Module *module;
  391. {
  392.     if (escapedthingbuf == NULL)
  393.       escapedthingbuf = xmalloc(BUFSIZE);
  394.     if (module->filename == NULL) {
  395.     /* (should be an error?) */
  396.     return FALSE;
  397.     }
  398.     fp = fopen(module->filename, "w");
  399.     if (fp != NULL) {
  400.     /* Write the definition of this game module. */
  401.     start_form(key(K_GAME_MODULE));
  402.     add_to_form(escaped_string(module->name));  newline_form();
  403.     if (module->defall) {
  404.         write_str_prop(key(K_TITLE), module->title,
  405.                "", 1, 0);
  406.         write_str_prop(key(K_VERSION), module->version,
  407.                "", 1, 0);
  408.         write_str_prop(key(K_BLURB), module->blurb,
  409.                "", 1, 0);
  410.         write_str_prop(key(K_BASE_MODULE), module->basemodulename,
  411.                "", 1, 0);
  412.         write_str_prop(key(K_PROGRAM_VERSION), version_string(),
  413.                "", 1, 0);
  414.         /* etc */
  415.     }
  416.     newline_form();
  417.     end_form();  newline_form();  newline_form();
  418.     if (module->defall || module->deftypes)
  419.       write_types();
  420.     if (module->defall || module->deftables)
  421.       write_tables();
  422.     if (module->defall || module->defglobals)
  423.       write_globals();
  424.     if (1 /* need to suppress synthesis after reload */) {
  425.       start_form(key(K_SET));
  426.       add_to_form("synthesis-methods");
  427.       add_to_form("nil");
  428.       end_form();
  429.       newline_form();
  430.     }
  431.     if (module->defall || module->defscoring)
  432.       write_scorekeepers();
  433.     doreshape = reshape_the_output(module);
  434.     reshaper = module;
  435.     if (module->defall || module->defworld)
  436.       write_world();
  437.     if (module->defall || module->defareas)
  438.       write_areas(module);
  439.     if (module->defall || module->defsides)
  440.       write_sides(module);
  441.     if (module->defall || module->defplayers)
  442.       write_players();
  443.     if (module->defall || module->defunits)
  444.       write_units(module);
  445.     if (module->defall || module->defhistory)
  446.       write_history();
  447.     /* Write the game notes here (seems reasonable, no deeper reason). */
  448.     if (module->instructions != lispnil) {
  449.         start_form(key(K_GAME_MODULE));  space_form();
  450.         write_lisp_prop(key(K_INSTRUCTIONS), module->instructions,
  451.                 lispnil, 0, FALSE, 1);
  452.         newline_form();  end_form();  newline_form();  newline_form();
  453.     }
  454.     if (module->notes != lispnil) {
  455.         start_form(key(K_GAME_MODULE));  space_form();
  456.         write_lisp_prop(key(K_NOTES), module->notes,
  457.                 lispnil, 0, FALSE, 1);
  458.         newline_form();  end_form();  newline_form();  newline_form();
  459.     }
  460.     if (module->designnotes != lispnil) {
  461.         start_form(key(K_GAME_MODULE));  space_form();
  462.         write_lisp_prop(key(K_DESIGN_NOTES), module->designnotes,
  463.                 lispnil, 0, FALSE, 1);
  464.         newline_form();  end_form();  newline_form();  newline_form();
  465.     }
  466.     fclose(fp);
  467.     return TRUE;
  468.     } else {
  469.     return FALSE;
  470.     }
  471. }
  472.  
  473. /* Write definitions of all the types. */
  474.  
  475. static void
  476. write_types()
  477. {
  478.     int u, m, t, i, ival;
  479.     char *typename, *sval;
  480.     Obj *obj;
  481.  
  482.     /* (or write out all the default values first for doc, then
  483.        only write changed values) */
  484.  
  485.     for_all_unit_types(u) {
  486.     start_form(key(K_UNIT_TYPE));
  487.     typename = shortest_escaped_name(u);
  488.     add_to_form(typename);
  489.     newline_form();
  490.     for (i = 0; utypedefns[i].name != NULL; ++i) {
  491.         if (utypedefns[i].intgetter) {
  492.         ival = (*(utypedefns[i].intgetter))(u);
  493.         write_num_prop(utypedefns[i].name, ival,
  494.                    utypedefns[i].dflt, 0, 1);
  495.         } else if (utypedefns[i].strgetter) {
  496.         sval = (*(utypedefns[i].strgetter))(u);
  497.         /* Special-case a couple possibly-redundant slots. */
  498.         if (utypedefns[i].strgetter == u_type_name
  499.             && strcmp(typename, sval) == 0)
  500.           continue;
  501.         if (utypedefns[i].strgetter == u_internal_name
  502.             && strcmp(typename, sval) == 0)
  503.           continue;
  504.         write_str_prop(utypedefns[i].name, sval,
  505.                    utypedefns[i].dfltstr, 0, 1);
  506.         } else {
  507.         obj = (*(utypedefns[i].objgetter))(u);
  508.         write_lisp_prop(utypedefns[i].name, obj,
  509.                 lispnil, FALSE, FALSE, TRUE);
  510.         }
  511.     }
  512.     end_form();  newline_form();
  513.     }
  514.     for_all_material_types(m) {
  515.     start_form(key(K_MATERIAL_TYPE));
  516.     add_to_form(escaped_symbol(m_type_name(m)));  newline_form();
  517.     for (i = 0; mtypedefns[i].name != NULL; ++i) {
  518.         if (mtypedefns[i].intgetter) {
  519.         ival = (*(mtypedefns[i].intgetter))(m);
  520.         write_num_prop(mtypedefns[i].name, ival,
  521.                    mtypedefns[i].dflt, 0, 1);
  522.         } else if (mtypedefns[i].strgetter) {
  523.         sval = (*(mtypedefns[i].strgetter))(m);
  524.         /* Special-case a a possibly-redundant slot. */
  525.         if (mtypedefns[i].strgetter == m_type_name
  526.             && strcmp(typename, sval) == 0)
  527.           continue;
  528.         write_str_prop(mtypedefns[i].name, sval,
  529.                    mtypedefns[i].dfltstr, 0, 1);
  530.         } else {
  531.         obj = (*(mtypedefns[i].objgetter))(m);
  532.         write_lisp_prop(mtypedefns[i].name, obj,
  533.                 lispnil, FALSE, FALSE, TRUE);
  534.         }
  535.     }
  536.     end_form();  newline_form();
  537.     }
  538.     for_all_terrain_types(t) {
  539.     start_form(key(K_TERRAIN_TYPE));
  540.     add_to_form(escaped_symbol(t_type_name(t)));  newline_form();
  541.     for (i = 0; ttypedefns[i].name != NULL; ++i) {
  542.         if (ttypedefns[i].intgetter) {
  543.         ival = (*(ttypedefns[i].intgetter))(t);
  544.         write_num_prop(ttypedefns[i].name, ival,
  545.                    ttypedefns[i].dflt, 0, 1);
  546.         } else if (ttypedefns[i].strgetter) {
  547.         sval = (*(ttypedefns[i].strgetter))(t);
  548.         /* Special-case a a possibly-redundant slot. */
  549.         if (ttypedefns[i].strgetter == t_type_name
  550.             && strcmp(typename, sval) == 0)
  551.           continue;
  552.         write_str_prop(ttypedefns[i].name, sval,
  553.                    ttypedefns[i].dfltstr, 0, 1);
  554.         } else {
  555.         obj = (*(ttypedefns[i].objgetter))(t);
  556.         write_lisp_prop(ttypedefns[i].name, obj,
  557.                 lispnil, FALSE, FALSE, TRUE);
  558.         }
  559.     }
  560.     end_form();  newline_form();
  561.     }
  562.     newline_form();
  563. }
  564.  
  565. /* Write definitions of all the tables. */
  566.  
  567. static void
  568. write_tables()
  569. {
  570.     int tbl;
  571.  
  572.     newline_form();
  573.     for (tbl = 0; tabledefns[tbl].name != 0; ++tbl) {
  574.     if (*(tabledefns[tbl].table) != NULL) {
  575.         write_table(tabledefns[tbl].name,
  576.             tabledefns[tbl].getter, tabledefns[tbl].dflt,
  577.             tabledefns[tbl].index1, tabledefns[tbl].index2);
  578.     }
  579.     }
  580. }
  581.  
  582. #define star_from_typ(typ)  \
  583.   ((typ) == UTYP ? "u*" : ((typ) == MTYP ? "m*" :"t*"))
  584.  
  585. #define name_from_typ(typ, i)  \
  586.   ((typ) == UTYP ? shortest_escaped_name(i) : ((typ) == MTYP ? m_type_name(i) : t_type_name(i)))
  587.  
  588. static void
  589. write_type_name_list(typ, flags, dim)
  590. int typ, *flags, dim;
  591. {
  592.     int j, first = TRUE, listlen = 0;
  593.  
  594.     if (flags == NULL)
  595.       return;
  596.     for (j = 0; j < dim; ++j)
  597.       if (flags[j])
  598.         ++listlen;
  599.     if (listlen > 1)
  600.       fprintf(fp, "(");
  601.     for (j = 0; j < dim; ++j) {
  602.     if (flags[j]) {
  603.         if (first)
  604.           first = FALSE;
  605.         else
  606.           fprintf(fp, " ");
  607.         fprintf(fp, "%s", escaped_symbol(name_from_typ(typ, j)));
  608.     }
  609.     }
  610.     if (listlen > 1)
  611.       end_form();
  612. }
  613.  
  614. #if 0
  615. /* Write out a list of values in a table. */
  616.  
  617. static void
  618. write_type_value_list(typ, flags, dim, getter, i)
  619. int typ, *flags, dim, (*getter) PROTO ((int, int)), i;
  620. {
  621.     int j, first = TRUE, listlen = 0;
  622.  
  623.     for (j = 0; j < dim; ++j)
  624.       if (flags == NULL || flags[j])
  625.         ++listlen;
  626.     if (listlen > 1)
  627.       fprintf(fp, "(");
  628.     for (j = 0; j < dim; ++j) {
  629.     if (flags == NULL || flags[j]) {
  630.         if (first)
  631.           first = FALSE;
  632.         else
  633.           fprintf(fp, " ");
  634.         fprintf(fp, "%d", (*getter)(i, j));
  635.     }
  636.     }
  637.     if (listlen > 1)
  638.       end_form();
  639. }
  640. #endif
  641.  
  642. /* A simple histogram struct - count and value, that's all. */
  643.  
  644. struct histo { int count, val; };
  645.  
  646. /* Sort into *descending* order by count. */
  647.  
  648. static int
  649. histo_compare(x, y)
  650. CONST void *x, *y;
  651. {
  652.     return ((struct histo *) y)->count - ((struct histo *) x)->count;
  653. }
  654.  
  655. /* Write out a single table.  Only write it if it contains non-default
  656.    values, and try to find runs of constant value, since tables can be
  657.    really large, but often have constant areas within them. */
  658.  
  659. static void
  660. write_table(name, getter, dflt, typ1, typ2)
  661. char *name;
  662. int (*getter) PROTO ((int, int)), dflt, typ1, typ2;
  663. {
  664.     int i, j, k, colvalue, constcol, next;
  665.     int numrandoms, nextrowdiffers, writeconst;
  666.     int sawfirst, constrands, constval;
  667.     int dim1 = numtypes_from_index_type(typ1);
  668.     int dim2 = numtypes_from_index_type(typ2);
  669.     struct histo mostcommon[200]; /* needs to be more than MAXxTYPES */
  670.     int indexes1[200], randoms[200];
  671.     int firstclause = TRUE;
  672.  
  673.     start_form(key(K_TABLE));
  674.     add_to_form(name);
  675.     fprintf(fp, "  ; %d\n", dflt);
  676.     if (dim1 <= dim2) {
  677.         /* Analyze the table by rows. */
  678.     for (k = 0; k < dim1; ++k)
  679.       indexes1[k] = FALSE;
  680.     for (i = 0; i < dim1; ++i) {
  681.         /* First see if this row has all the same values as the next. */
  682.         indexes1[i] = TRUE;
  683.         nextrowdiffers = FALSE;
  684.         if (i < dim1 - 1) {
  685.             for (j = 0; j < dim2; ++j) {
  686.                 if ((*getter)(i, j) != (*getter)(i + 1, j)) {
  687.                     nextrowdiffers = TRUE;
  688.                     break;
  689.                 }
  690.             }
  691.         } else {
  692.             /* The last row is *always* "different". */
  693.             nextrowdiffers = TRUE;
  694.         }
  695.         /* (should look at *all* rows to find matching rows before
  696.            dumping one) */
  697.         if (nextrowdiffers) {
  698.         /* Make a histogram of all the values in this row. */
  699.         mostcommon[0].count = 1;
  700.         mostcommon[0].val = (*getter)(i, 0);
  701.         next = 1;
  702.         for (j = 0; j < dim2; ++j) {
  703.             for (k = 0; k < next; ++k) {
  704.             if (mostcommon[k].val == (*getter)(i, j)) {
  705.                 ++(mostcommon[k].count);
  706.                 break;
  707.             }
  708.             }
  709.             if (k == next) {
  710.             mostcommon[next].count = 1;
  711.             mostcommon[next].val = (*getter)(i, j);
  712.             ++next;
  713.             }
  714.         }
  715.         if (next == 1 && mostcommon[0].val == dflt) {
  716.             /* Entire row(s) is/are just the default table value. */
  717.         } else {
  718.             writeconst = FALSE;
  719.             numrandoms = 0;
  720.             if (next == 1) {
  721.             /* Only one value in the row(s). */
  722.             writeconst = TRUE;
  723.             } else {
  724.             qsort(mostcommon, next, sizeof(struct histo),
  725.                   histo_compare);
  726.             if (mostcommon[0].count >= (3 * dim2) / 4) {
  727.                 /* The most common value in this row(s) is not the only value,
  728.                    but it is worth writing into a separate clause. */
  729.                 writeconst = TRUE;
  730.                 for (j = 0; j < dim2; ++j) {
  731.                 /* Flag the other values as needing to be
  732.                    written separately. */
  733.                 randoms[j] =
  734.                   (mostcommon[0].val != (*getter)(i, j));
  735.                 if (randoms[j])
  736.                   ++numrandoms;
  737.                 }
  738.             } else {
  739.                 /* Flag all in the row as randoms. */
  740.                 for (j = 0; j < dim2; ++j) {
  741.                 randoms[j] = TRUE;
  742.                 ++numrandoms;
  743.                 }
  744.             }
  745.             }
  746.             /* Write out the most common value (if non-default) in the row(s),
  747.                expressing it with a clause that applies the value
  748.                to the entire row(s). */
  749.             if (writeconst && mostcommon[0].val != dflt) {
  750.             if (firstclause)
  751.               firstclause = FALSE;
  752.             else
  753.               newline_form();
  754.             fprintf(fp, "  (");
  755.             write_type_name_list(typ1, indexes1, dim1);
  756.             fprintf(fp, " %s %d", star_from_typ(typ2), mostcommon[0].val);
  757.             end_form();
  758.             }
  759.             /* Now override the most common value with any
  760.                exceptions. */
  761.             if (numrandoms > 0) {
  762.             constrands = TRUE;
  763.             sawfirst = FALSE;
  764.             for (j = 0; j < dim2; ++j) {
  765.                 if (randoms[j]) {
  766.                     if (!sawfirst) {
  767.                     constval = (*getter)(i, j);
  768.                     sawfirst = TRUE;
  769.                     }
  770.                     if (sawfirst && constval != (*getter)(i, j)) {
  771.                     constrands = FALSE;
  772.                     break;
  773.                     }
  774.                 }
  775.             }
  776.             if (constrands) {
  777.                 if (firstclause)
  778.                   firstclause = FALSE;
  779.                 else
  780.                   newline_form();
  781.                 fprintf(fp, "  (");
  782.                 write_type_name_list(typ1, indexes1, dim1);
  783.                 fprintf(fp, " ");
  784.                 write_type_name_list(typ2, randoms, dim2);
  785.                 add_num_to_form(constval);
  786.                 end_form();
  787.             } else {
  788.                 /* We have a group of rows with varying data
  789.                    in the columns; write a separate row. */
  790.                 for (j = 0; j < dim2; ++j) {
  791.                 if (randoms[j]) {
  792.                     if (firstclause)
  793.                       firstclause = FALSE;
  794.                     else
  795.                       newline_form();
  796.                     fprintf(fp, "  (");
  797.                     write_type_name_list(typ1, indexes1, dim1);
  798.                     fprintf(fp, " %s %d",
  799.                             escaped_symbol(name_from_typ(typ2, j)),
  800.                             (*getter)(i, j));
  801.                     fprintf(fp, ")");
  802.                 }
  803.                 }
  804.             }
  805.             }
  806.         }
  807.         /* Reset the row flags in preparation for the next group
  808.            of rows whose contents match each other. */
  809.         for (k = 0; k < dim1; ++k)
  810.           indexes1[k] = FALSE;
  811.         }
  812.     }
  813.     } else {
  814.         /* Analyze the table by columns. */
  815.         /* Don't work as hard to optimize; this case should be uncommon,
  816.        since there are usually more types of units than
  817.        materials or terrain. */
  818.     for (j = 0; j < dim2; ++j) {
  819.         constcol = TRUE;
  820.         colvalue = (*getter)(0, j);
  821.         for (i = 0; i < dim1; ++i) {
  822.         if ((*getter)(i, j) != colvalue) {
  823.             constcol = FALSE;
  824.             break;
  825.         }
  826.         }
  827.         if (!constcol || colvalue != dflt) {
  828.         if (firstclause)
  829.           firstclause = FALSE;
  830.         else
  831.           newline_form();
  832.         fprintf(fp, "  (%s %s",
  833.             star_from_typ(typ1),
  834.             escaped_symbol(name_from_typ(typ2, j)));
  835.         /* Write out either a single constant value or a list of
  836.            varying values, as appropriate. */
  837.         if (constcol) {
  838.             add_num_to_form(colvalue);
  839.         } else {
  840.             fprintf(fp, " (");
  841.             for (i = 0; i < dim1; ++i) {
  842.             add_num_to_form((*getter)(i, j));
  843.             }
  844.             end_form();
  845.         }
  846.         end_form();
  847.         }
  848.     }
  849.     }
  850.     end_form();  newline_form();
  851. }
  852.  
  853. /* Write info about the whole world. */
  854.  
  855. static void
  856. write_world()
  857. {
  858.     newline_form();
  859.     start_form(key(K_WORLD));
  860.     add_num_to_form((doreshape ? reshaper->finalcircumference : world.circumference));
  861.     write_num_prop(key(K_DAY_LENGTH), world.daylength, 1, 0, 1);
  862.     write_num_prop(key(K_YEAR_LENGTH), world.yearlength, 1, 0, 1);
  863.     end_form();  newline_form();
  864. }
  865.  
  866. /* Write info about the area in the world.  This code uses run-length encoding
  867.    to reduce the size of each written layer as much as possible.  Note
  868.    also that each layer is written as a separate form, so that the Lisp
  869.    reader doesn't have to read really large forms back in. */
  870.  
  871. static void
  872. write_areas(module)
  873. Module *module;
  874. {
  875.     int all = module->defall, compress = module->compresslayers;
  876.  
  877.     newline_form();
  878.     /* Write the basic dimensions. */
  879.     start_form(key(K_AREA));
  880.     add_num_to_form((doreshape ? reshaper->finalwidth : area.width));
  881.     add_num_to_form((doreshape ? reshaper->finalheight : area.height));
  882.     /* Write all the scalar properties. */
  883.     write_num_prop(key(K_LATITUDE), area.latitude, 0, 0, 0);
  884.     write_num_prop(key(K_LONGITUDE), area.longitude, 0, 0, 0);
  885.     write_num_prop(key(K_CELL_WIDTH), area.cellwidth, 0, 0, 0);
  886.     end_form();
  887.     newline_form();
  888.     /* Write the area's layers, each as a separate form. */
  889.     if (all || module->defareaterrain)
  890.       write_area_terrain(compress);
  891.     if (all || module->defareaterrain)
  892.       write_area_aux_terrain(compress);
  893.     if (all || module->defareamisc)
  894.       write_area_features(compress);
  895.     if (all || module->defareamisc)
  896.       write_area_elevations(compress);
  897.     if (all || module->defareamisc)
  898.       write_area_people_sides(compress);
  899.     if (all || module->defareamaterial)
  900.       write_area_materials(compress);
  901.     if (all || module->defareaweather)
  902.       write_area_temperatures(compress);
  903.     if (all || module->defareaweather)
  904.       write_area_clouds(compress);
  905.     if (all || module->defareaweather)
  906.       write_area_winds(compress);
  907. }
  908.  
  909. static void
  910. write_area_terrain(compress)
  911. int compress;
  912. {
  913.     int t;
  914.  
  915.     start_form(key(K_AREA));  space_form();
  916.     start_form(key(K_TERRAIN));  newline_form();
  917.     fprintf(fp, "  ");
  918.     start_form(key(K_BY_NAME));
  919.     for_all_terrain_types(t) {
  920.     /* Break the list into groups of 5 per line. */
  921.         if (t % 5 == 0) {
  922.         newline_form(); fprintf(fp, "   ");
  923.     }
  924.         fprintf(fp, " (%s %d)", escaped_symbol(t_type_name(t)), t);
  925.     }
  926.     end_form();  newline_form();
  927.     write_rle(fn_terrain_at, 0, numttypes-1, NULL, compress);
  928.     end_form();  end_form();  newline_form();
  929. }
  930.  
  931. static void
  932. write_area_aux_terrain(compress)
  933. int compress;
  934. {
  935.     int t;
  936.  
  937.     for_all_terrain_types(t) {
  938.     if (aux_terrain_defined(t)) {
  939.         start_form(key(K_AREA));  space_form();
  940.         start_form(key(K_AUX_TERRAIN));
  941.         add_to_form(escaped_symbol(t_type_name(t)));
  942.         newline_form();
  943.         tmpttype = t;
  944.         write_rle(fn_aux_terrain_at, 0, 127, NULL, compress);
  945.         end_form();  end_form();  newline_form();
  946.     }
  947.     }
  948. }
  949.  
  950. static void
  951. write_area_features(compress)
  952. int compress;
  953. {
  954.     Feature *feature;
  955.     extern Feature *featurelist;
  956.  
  957.     if (featurelist == NULL || !features_defined()) return;
  958.     renumber_features();
  959.     start_form(key(K_AREA));  space_form();
  960.     start_form(key(K_FEATURES));
  961.     fprintf(fp, " (\n");
  962.     /* Dump out the list of features first. */
  963.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  964.     fprintf(fp, "   (%d %s",
  965.         feature->id, escaped_string(feature->typename));
  966.     fprintf(fp, " %s)\n",
  967.         escaped_string(feature->name));
  968.     }
  969.     fprintf(fp, "  )\n");
  970.     /* Now record which features go with which cells. */
  971.     write_rle(fn_feature_at, 0, -1, NULL, compress);
  972.     fprintf(fp, "))\n");
  973. }
  974.  
  975. static void
  976. write_area_elevations(compress)
  977. int compress;
  978. {
  979.     if (elevations_defined()) {
  980.     start_form(key(K_AREA));  space_form();
  981.     start_form(key(K_ELEVATIONS));
  982.     newline_form();
  983.     write_rle(fn_elevation_at, minelev, maxelev, NULL, compress);
  984.     end_form();  end_form();  newline_form();
  985.     }
  986. }
  987.  
  988. static void
  989. write_area_people_sides(compress)
  990. int compress;
  991. {
  992.     if (people_sides_defined()) {
  993.     start_form(key(K_AREA));  space_form();
  994.     start_form(key(K_PEOPLE_SIDES));
  995.     newline_form();
  996.     write_rle(fn_people_side_at, 0, MAXSIDES+1, NULL, compress);
  997.     end_form();  end_form();  newline_form();
  998.     }
  999. }
  1000.  
  1001. static void
  1002. write_area_materials(compress)
  1003. int compress;
  1004. {
  1005.     int m;
  1006.  
  1007.     if (any_cell_materials_defined()) {
  1008.     for_all_material_types(m) {
  1009.         if (cell_material_defined(m)) {
  1010.         start_form(key(K_AREA));  space_form();
  1011.         start_form(key(K_MATERIAL));
  1012.         add_to_form(escaped_symbol(m_type_name(m)));
  1013.         newline_form();
  1014.         tmpmtype = m;
  1015.         write_rle(fn_material_at, 0, 127, NULL, compress);
  1016.         end_form(); end_form(); newline_form();
  1017.         }
  1018.     }
  1019.     }
  1020. }
  1021.  
  1022. static void
  1023. write_area_temperatures(compress)
  1024. int compress;
  1025. {
  1026.     if (temperatures_defined()) {
  1027.     start_form(key(K_AREA));  space_form();
  1028.     start_form(key(K_TEMPERATURES));
  1029.     newline_form();
  1030.     write_rle(fn_temperature_at, 0, 9999, NULL, compress);
  1031.     end_form(); end_form(); newline_form();
  1032.     }
  1033. }
  1034.  
  1035. static void
  1036. write_area_clouds(compress)
  1037. int compress;
  1038. {
  1039.     if (clouds_defined()) {
  1040.     start_form(key(K_AREA));  space_form();
  1041.     start_form(key(K_CLOUDS));
  1042.     newline_form();
  1043.     write_rle(fn_raw_cloud_at, 0, 127, NULL, compress);
  1044.     end_form(); end_form(); newline_form();
  1045.     }
  1046.     if (cloud_bottoms_defined()) {
  1047.     start_form(key(K_AREA));  space_form();
  1048.     start_form(key(K_CLOUD_BOTTOMS));
  1049.     newline_form();
  1050.     write_rle(fn_raw_cloud_bottom_at, 0, 9999, NULL, compress);
  1051.     end_form(); end_form(); newline_form();
  1052.     }
  1053.     if (cloud_heights_defined()) {
  1054.     start_form(key(K_AREA));  space_form();
  1055.     start_form(key(K_CLOUD_HEIGHTS));
  1056.     newline_form();
  1057.     write_rle(fn_raw_cloud_height_at, 0, 9999, NULL, compress);
  1058.     end_form(); end_form(); newline_form();
  1059.     }
  1060. }
  1061.  
  1062. static void
  1063. write_area_winds(compress)
  1064. int compress;
  1065. {
  1066.     if (winds_defined()) {
  1067.     start_form(key(K_AREA));  space_form();
  1068.     start_form(key(K_WINDS));
  1069.     newline_form();
  1070.     write_rle(fn_raw_wind_at, 0, 127, NULL, compress);
  1071.     end_form(); end_form(); newline_form();
  1072.     }
  1073. }
  1074.  
  1075. /* Write the globals.  The "complete" flag forces all values out, even
  1076.    if they match the compiled-in defaults. */
  1077.  
  1078. /* These decls are needed because the functions are mentioned in gvar.def. */
  1079.  
  1080. static void
  1081. write_globals()
  1082. {
  1083.     int complete = FALSE;
  1084.     time_t now;
  1085.  
  1086.     /* Snapshot realtime values. */
  1087.     time(&now);
  1088.     set_g_elapsed_time(idifftime(now, game_start_in_real_time));
  1089.  
  1090.     newline_form();
  1091.  
  1092. #undef  DEF_VAR_I
  1093. #define DEF_VAR_I(STR,FNAME,setfname,doc,var,lo,DFLT,hi)  \
  1094.     if (complete || FNAME() != DFLT)  { \
  1095.       start_form(key(K_SET));  \
  1096.       fprintf(fp, " %s %d)\n", STR, FNAME());  \
  1097.     }
  1098. #undef  DEF_VAR_S
  1099. #define DEF_VAR_S(STR,FNAME,setfname,doc,var,DFLT)  \
  1100.     if (complete || string_not_default(FNAME(), DFLT))  { \
  1101.       start_form(key(K_SET));  \
  1102.       fprintf(fp, " %s %s)\n", STR, escaped_string(FNAME()));  \
  1103.     }
  1104. #undef  DEF_VAR_L
  1105. #define DEF_VAR_L(STR,FNAME,setfname,doc,var,DFLT)  \
  1106.     if (complete || ((DFLT) == NULL && FNAME() != lispnil))  {  \
  1107.       if (FNAME() != NULL) {  \
  1108.         start_form(key(K_SET));  \
  1109.         fprintf(fp, " %s ", STR);  \
  1110.         fprintlisp(fp, FNAME());  \
  1111.         fprintf(fp, ")\n");  \
  1112.       } else {  \
  1113.         fprintf(fp, "; %s was unbound?\n", STR);  \
  1114.       }  \
  1115.     }
  1116.  
  1117. #include "gvar.def"
  1118.  
  1119. }
  1120.  
  1121. /* Write all the scorekeepers. */
  1122.  
  1123. static void
  1124. write_scorekeepers()
  1125. {
  1126.     Scorekeeper *sk;
  1127.  
  1128.     for_all_scorekeepers(sk) {
  1129.     start_form(key(K_SCOREKEEPER));  add_num_to_form(sk->id);
  1130.     write_str_prop(key(K_TITLE), sk->title, "", 0, 1);
  1131.     write_lisp_prop(key(K_WHEN), sk->when, lispnil, 0, FALSE, 1);
  1132.     write_lisp_prop(key(K_APPLIES_TO), sk->who, lispnil, 0, FALSE, 1);
  1133.     write_lisp_prop(key(K_KNOWN_TO), sk->who, lispnil, 0, FALSE, 1);
  1134.     write_lisp_prop(key(K_TRIGGER), sk->trigger, lispnil, 0, FALSE, 1);
  1135.     write_lisp_prop(key(K_DO), sk->body, lispnil, 0, FALSE, 1);
  1136.     write_num_prop(key(K_TRIGGERED), sk->triggered, 0, 0, 1); 
  1137.     write_num_prop(key(K_INITIAL), sk->initial, 0, 0, 1); 
  1138.     write_lisp_prop(key(K_NOTES), sk->notes, lispnil, 0, FALSE, 1);
  1139.     end_form();  newline_form();
  1140.     }
  1141. }
  1142.  
  1143. /* Write declarations of all the sides. */
  1144.  
  1145. static void
  1146. write_sides(module)
  1147. Module *module;
  1148. {
  1149.     Side *side;
  1150.  
  1151.     fprintf(fp, "\n; %d sides\n", numsides);
  1152.     Dprintf("Will try to write %d sides ...\n", numsides);
  1153.     for_all_sides(side) {
  1154.     start_form(key(K_SIDE));  add_num_to_form(side->id);
  1155.     write_side_properties(side);
  1156.     end_form();  newline_form();
  1157.     if (module->defall || module->defsideviews)
  1158.       write_side_view(side, module->compresslayers);
  1159.     Dprintf("  Wrote side %s\n", side_desig(side));
  1160.     }
  1161.     Dprintf("... Done writing sides\n");
  1162. }
  1163.  
  1164. /* Write random properties of a side. */
  1165.  
  1166. static void
  1167. write_side_properties(side)
  1168. Side *side;
  1169. {
  1170.     int i;
  1171.  
  1172.     write_str_prop(key(K_NAME), side->name, "", 0, 1);
  1173.     write_str_prop(key(K_LONG_NAME), side->longname, "", 0, 1);
  1174.     write_str_prop(key(K_SHORT_NAME), side->shortname, "", 0, 1);
  1175.     write_str_prop(key(K_NOUN), side->noun, "", 0, 1);
  1176.     write_str_prop(key(K_PLURAL_NOUN), side->pluralnoun, "", 0, 1);
  1177.     write_str_prop(key(K_ADJECTIVE), side->adjective, "", 0, 1);
  1178.     write_str_prop(key(K_COLOR), side->colorscheme, "", 0, 1);
  1179.     write_str_prop(key(K_EMBLEM_NAME), side->emblemname, "", 0, 1);
  1180.     write_str_prop(key(K_CLASS), side->sideclass, "", 0, 1);
  1181.     write_utype_string_list(key(K_UNIT_NAMERS), side->unitnamers, "", 1);
  1182.     write_bool_prop(key(K_ACTIVE), side->ingame, FALSE, 0, 1);
  1183.     write_num_prop(key(K_PRIORITY), side->priority, 0, 0, 1);
  1184.     write_num_prop(key(K_STATUS), side->status, 0, 0, 1);
  1185.     write_num_prop(key(K_TURN_TIME_USED), side->turntimeused, 0, 0, 1);
  1186.     write_num_prop(key(K_TOTAL_TIME_USED), side->totaltimeused, 0, 0, 1);
  1187.     write_num_prop(key(K_FINISHED_TURN), side->finishedturn, 0, 0, 1);
  1188.     write_num_prop(key(K_CONTROLLED_BY), side_number(side->controlledby), 0, 0, 1);
  1189.     write_side_value_list(key(K_TRUSTS), side->trusts, 0, 1);
  1190.     write_side_value_list(key(K_TRADES), side->trades, 0, 1);
  1191.     write_utype_value_list(key(K_START_WITH), side->startwith, 0, 1);
  1192.     write_utype_value_list(key(K_NEXT_NUMBERS), side->counts, 0, 1);
  1193.     write_utype_value_list(key(K_TECH), side->tech, 0, 1);
  1194.     write_utype_value_list(key(K_INIT_TECH), side->inittech, 0, 1);
  1195.     /* (should do this with a generic array-writing routine) */
  1196.     if (side->scores) {
  1197.     newline_form();
  1198.     start_form(key(K_SCORES));
  1199.     for (i = 0; i < numscores; ++i) {
  1200.         add_num_to_form(side->scores[i]);
  1201.     }
  1202.     end_form();
  1203.     newline_form();
  1204.     }
  1205.     if (side_has_ai(side)) {
  1206.     newline_form();
  1207.     start_form(key(K_AI_DATA));
  1208.     ai_write_state(fp, side);
  1209.     end_form();
  1210.     newline_form();
  1211.     }
  1212. }
  1213.  
  1214. /* Write about what has been seen in the area. */
  1215.  
  1216. /* (should have option to spec symbolic dict of sides and units) */
  1217.  
  1218. static int
  1219. fn_terrain_view(x, y)
  1220. int x, y;
  1221. {
  1222.     return terrain_view(tmpside, x, y);
  1223. }
  1224.  
  1225. static int
  1226. fn_unit_view(x, y)
  1227. int x, y;
  1228. {
  1229.     return unit_view(tmpside, x, y);
  1230. }
  1231.  
  1232. static int
  1233. fn_unit_view_date(x, y)
  1234. int x, y;
  1235. {
  1236.     return unit_view_date(tmpside, x, y);
  1237. }
  1238.  
  1239. static void
  1240. write_side_view(side, compress)
  1241. Side *side;
  1242. int compress;
  1243. {
  1244.     /* View layers are not defined if see-all is in effect. */
  1245.     if (g_see_all())
  1246.       return;
  1247.     tmpside = side;
  1248.     newline_form();
  1249.     start_form(key(K_SIDE));  add_num_to_form(side->id);  space_form();
  1250.     start_form(key(K_TERRAIN_VIEW));  newline_form();
  1251.     write_rle(fn_terrain_view, 0, 10000, NULL, compress);
  1252.     end_form();  end_form();  newline_form();
  1253.     start_form(key(K_SIDE));  add_num_to_form(side->id);  space_form();
  1254.     start_form(key(K_UNIT_VIEW));  newline_form();
  1255.     write_rle(fn_unit_view, 0, 10000, NULL, compress);
  1256.     end_form();  end_form();  newline_form();
  1257.     start_form(key(K_SIDE));  add_num_to_form(side->id);  space_form();
  1258.     start_form(key(K_UNIT_VIEW_DATES));  newline_form();
  1259.     write_rle(fn_unit_view_date, 0, 10000, NULL, compress);
  1260.     end_form();  end_form();  newline_form();
  1261. }
  1262.  
  1263. static void
  1264. write_players()
  1265. {
  1266.     Side *side;
  1267.  
  1268.     fprintf(fp, "; %d players\n", numplayers);
  1269.     Dprintf("Will try to write %d players ...\n", numplayers);
  1270.     for_all_sides(side) {
  1271.     if (side->player != NULL) {
  1272.         write_player(side->player);
  1273.         Dprintf("Wrote player %s,\n", player_desig(side->player));
  1274.     }
  1275.     }
  1276.     Dprintf("... Done writing players.\n");
  1277. }
  1278.  
  1279. static void
  1280. write_player(player)
  1281. Player *player;
  1282. {
  1283.     start_form(key(K_PLAYER));  add_num_to_form(0);  newline_form();
  1284.     write_str_prop(key(K_NAME), player->name, "", 0, 1);
  1285.     write_str_prop(key(K_CONFIG_NAME), player->configname, "", 0, 1);
  1286.     write_str_prop(key(K_DISPLAY_NAME), player->displayname, "", 0, 1);
  1287.     write_str_prop(key(K_AI_TYPE_NAME), player->aitypename, "", 0, 1);
  1288.     end_form();  newline_form();
  1289. }
  1290.  
  1291. /* Should write out "unit groups" with dict prepended, then can use with
  1292.    multiple games */
  1293.  
  1294. /* Write the unit section of a game module. */
  1295.  
  1296. static void
  1297. write_units(module)
  1298. Module *module;
  1299. {
  1300.     int x, y;
  1301.     Unit *unit;
  1302.     Side *loopside;
  1303.  
  1304.     /* Make sure no dead units get saved. */
  1305.     flush_dead_units();
  1306.     /* Make a consistent ordering. */
  1307.     sort_units();
  1308.     fprintf(fp, "; %d units\n", numunits);
  1309.     /* Need to write out the defaults being assumed subsequently. */
  1310.     /* maybe use those in postprocessing. */
  1311.     fprintf(fp, "(unit-defaults)\n");
  1312.     Dprintf("Writing %d units ...\n", numunits);
  1313.     for_all_sides_plus_indep(loopside) {
  1314.     for_all_side_units(loopside, unit) {
  1315.         if (alive(unit)) {
  1316.         if (doreshape) {
  1317.             reshaped_point(unit->x, unit->y, &x, &y);
  1318.         } else {
  1319.             x = unit->x;  y = unit->y;
  1320.         }
  1321.         start_form(shortest_escaped_name(unit->type));
  1322.         fprintf(fp, " %d %d %d", x, y, side_number(unit->side));
  1323.         write_num_prop(key(K_Z), unit->z, 0, 0, 0);
  1324.         write_str_prop(key(K_N), unit->name, NULL, 0, 0);
  1325.         /* Maybe write the unit's id. */
  1326.         if (module->defall || module->defunitids || unit->occupant)
  1327.           write_num_prop(key(K_SHARP), unit->id, 0, 0, 0);
  1328.         /* Need this to get back into the right transport. */
  1329.         if (unit->transport)
  1330.           write_num_prop(key(K_IN), unit->transport->id, 0, 0, 0);
  1331.         /* Write optional info about the units. */
  1332.         if (module->defall || module->defunitprops)
  1333.           write_unit_properties(unit);
  1334.         if (module->defall || module->defunitacts)
  1335.           write_unit_act(unit);
  1336.         if (module->defall || module->defunitplans)
  1337.           write_unit_plan(unit);
  1338.         /* close the unit out */
  1339.         end_form();
  1340.         newline_form();
  1341.         Dprintf("Wrote %s\n", unit_desig(unit));
  1342.         }
  1343.     }
  1344.     newline_form();
  1345.     }
  1346.     Dprintf("... Done writing units.\n");
  1347. }
  1348.  
  1349. /* Write random properties, but only if they have non-default values. */
  1350.  
  1351. static void
  1352. write_unit_properties(unit)
  1353. Unit *unit;
  1354. {
  1355.     write_num_prop(key(K_NB), unit->number, 0, 0, 0);
  1356.     write_num_prop(key(K_HP), unit->hp, u_hp(unit->type), 0, 0);
  1357.     write_num_prop(key(K_CP), unit->cp, u_cp(unit->type), 0, 0);
  1358.     write_num_prop(key(K_CXP), unit->cxp, 0, 0, 0);
  1359.     write_num_prop(key(K_MO), unit->morale, 0, 0, 0);
  1360.     write_utype_value_list(key(K_TP), unit->tooling, 0, 0);
  1361.     write_side_value_list(key(K_OPINIONS), unit->opinions, 0, 0);
  1362.     write_mtype_value_list(key(K_M), unit->supply, 0, 0);
  1363.     write_lisp_prop(key(K_X), unit->hook, lispnil, 0, TRUE, FALSE);
  1364. }
  1365.  
  1366. /* Write out the unit's current actor state. */
  1367.  
  1368. static void
  1369. write_unit_act(unit)
  1370. Unit *unit;
  1371. {
  1372.     int acp = u_acp(unit->type), atype, i, slen;
  1373.     ActorState *act = unit->act;
  1374.  
  1375.     /* Actor state is kind of meaningless for dead units. */
  1376.     if (!alive(unit))
  1377.       return;
  1378.     if (act != NULL
  1379.     && (act->acp != acp
  1380.         || act->initacp != acp
  1381.         || act->nextaction.type != A_NONE)) {
  1382.     if (1) {
  1383.        newline_form();  space_form();
  1384.     }
  1385.     space_form();
  1386.     start_form(key(K_ACT));
  1387.     if (act->acp != acp)
  1388.       write_num_prop(key(K_ACP), act->acp, acp, FALSE, FALSE);
  1389.     if (act->initacp != acp)
  1390.       write_num_prop(key(K_ACP0), act->initacp, acp, FALSE, FALSE);
  1391.     if (act->nextaction.type != A_NONE) {
  1392.         atype = act->nextaction.type;
  1393.         space_form();
  1394.         start_form(key(K_A));
  1395.         add_to_form(actiondefns[atype].name);
  1396.         slen = strlen(actiondefns[atype].argtypes);
  1397.             for (i = 0; i < slen; ++i)
  1398.           add_num_to_form(act->nextaction.args[i]);
  1399.             if (act->nextaction.actee != 0) {
  1400.                 space_form();
  1401.         add_num_to_form(act->nextaction.actee);
  1402.             }
  1403.             end_form();
  1404.     }
  1405.     end_form();
  1406.     }
  1407. }
  1408.  
  1409. /* Write out the unit's current plan. */
  1410.  
  1411. static void
  1412. write_unit_plan(unit)
  1413. Unit *unit;
  1414. {
  1415.     Task *task;
  1416.     Plan *plan = unit->plan;
  1417.  
  1418.     /* The plan is kind of meaningless for dead units. */
  1419.     if (!alive(unit))
  1420.       return;
  1421.     if (plan) {
  1422.         newline_form();  space_form();  space_form();
  1423.         start_form(key(K_PLAN));
  1424.         add_to_form(plantypenames[plan->type]);
  1425.     add_num_to_form(plan->creationturn);
  1426.     write_num_prop(key(K_START_TURN), plan->startturn, 0, 0, 0);
  1427.     write_num_prop(key(K_END_TURN), plan->endturn, 0, 0, 0);
  1428.     write_bool_prop(key(K_ASLEEP), plan->asleep, FALSE, 0, 0);
  1429.     write_bool_prop(key(K_RESERVE), plan->reserve, FALSE, 0, 0);
  1430.     write_bool_prop(key(K_DELAYED), plan->delayed, FALSE, 0, 0);
  1431.     write_bool_prop(key(K_WAIT), plan->waitingfortasks, FALSE, 0, 0);
  1432.     write_bool_prop(key(K_AUTOTASK), plan->autotask, FALSE, 0, 0);
  1433.     write_bool_prop(key(K_AI_CONTROL), plan->aicontrol, TRUE, 0, 0);
  1434.     write_bool_prop(key(K_SUPPLY_ALARM), plan->supply_alarm, TRUE, 0, 0);
  1435.     write_bool_prop(key(K_SUPPLY_IS_LOW), plan->supply_is_low, FALSE, 0, 0);
  1436.     write_bool_prop(key(K_WAIT_TRANSPORT), plan->waitingfortransport, FALSE, 0, 0);
  1437.     if (plan->maingoal)
  1438.       write_goal(plan->maingoal, K_GOAL);
  1439.     if (plan->formation)
  1440.       write_goal(plan->formation, K_FORMATION);
  1441.     if (plan->tasks) {
  1442.             space_form();
  1443.             start_form(key(K_TASKS));
  1444.         for (task = plan->tasks; task != NULL; task = task->next) {
  1445.             space_form();
  1446.             write_task(task);
  1447.         }
  1448.         end_form();
  1449.     }
  1450.     end_form();
  1451.     }
  1452. }
  1453.  
  1454. static void
  1455. write_task(task)
  1456. Task *task;
  1457. {
  1458.     int i, numargs;
  1459.     char *argtypes;
  1460.  
  1461.     start_form(taskdefns[task->type].name);
  1462.     add_num_to_form(task->execnum);
  1463.     add_num_to_form(task->retrynum);
  1464.     argtypes = taskdefns[task->type].argtypes;
  1465.     numargs = strlen(argtypes);
  1466.     for (i = 0; i < numargs; ++i)
  1467.       add_num_to_form(task->args[i]);
  1468.     end_form();
  1469. }
  1470.  
  1471. static void
  1472. write_goal(goal, keyword)
  1473. Goal *goal;
  1474. int keyword;
  1475. {
  1476.     int i, numargs;
  1477.     char *argtypes;
  1478.  
  1479.     space_form();
  1480.     start_form(key(keyword));
  1481.     add_num_to_form(side_number(goal->side));
  1482.     add_num_to_form(goal->tf);
  1483.     add_to_form(goaldefns[goal->type].name);
  1484.     argtypes = goaldefns[goal->type].argtypes;
  1485.     numargs = strlen(argtypes);
  1486.     for (i = 0; i < numargs; ++i)
  1487.       add_num_to_form(goal->args[i]);
  1488.     end_form();
  1489. }
  1490.  
  1491. /* Write all the historical events recorded so far. */
  1492.  
  1493. static void sort_past_units PROTO ((void));
  1494.  
  1495. static void
  1496. write_history()
  1497. {
  1498.     PastUnit *pastunit;
  1499.     HistEvent *hevt;
  1500.  
  1501.     sort_past_units();
  1502.     /* Write all the past units that might be mentioned in events. */
  1503.     /* (should sort these by descending (negative) id first) */
  1504.     for (pastunit = past_unit_list; pastunit != NULL; pastunit = pastunit->next)
  1505.       write_past_unit(pastunit);
  1506.     write_historical_event(history);
  1507.     for (hevt = history->next; hevt != history; hevt = hevt->next)
  1508.       write_historical_event(hevt);
  1509. }
  1510.  
  1511. static int compare_past_units PROTO ((CONST void *pu1, CONST void *pu2));
  1512.  
  1513. static int
  1514. compare_past_units(pu1, pu2)
  1515. CONST void *pu1, *pu2;
  1516. {
  1517.     return ((*((PastUnit **) pu2))->id - (*((PastUnit **) pu1))->id);
  1518. }
  1519.  
  1520. static void
  1521. sort_past_units()
  1522. {
  1523.     int numpast = 0, i;
  1524.     PastUnit *pastunit, **tmparray;
  1525.  
  1526.     for (pastunit = past_unit_list; pastunit != NULL; pastunit = pastunit->next)
  1527.       ++numpast;
  1528.     /* Don't bother "sorting" if no more than one past unit. */
  1529.     if (numpast <= 1)
  1530.       return;
  1531.     tmparray = (PastUnit **) xmalloc(numpast * sizeof(PastUnit *));
  1532.     i = 0;
  1533.     for (pastunit = past_unit_list; pastunit != NULL; pastunit = pastunit->next)
  1534.       tmparray[i++] = pastunit;
  1535.     qsort(tmparray, numpast, sizeof(PastUnit *), compare_past_units);
  1536.     for (i = 0; i < numpast - 1; ++i)
  1537.       tmparray[i]->next = tmparray[i + 1];
  1538.     tmparray[numpast - 1]->next = NULL;
  1539.     past_unit_list = tmparray[0];
  1540.     free(tmparray);
  1541. }
  1542.  
  1543. static void
  1544. write_past_unit(pastunit)
  1545. PastUnit *pastunit;
  1546. {
  1547.     start_form(key(K_EXU));
  1548.     add_num_to_form(pastunit->id);
  1549.     add_to_form(shortest_escaped_name(pastunit->type));
  1550.     add_num_to_form(pastunit->x);
  1551.     add_num_to_form(pastunit->y);
  1552.     add_num_to_form(side_number(pastunit->side));
  1553.     write_num_prop(key(K_Z), pastunit->z, 0, 0, 0);
  1554.     write_str_prop(key(K_N), pastunit->name, NULL, 0, 0);
  1555.     write_num_prop(key(K_NB), pastunit->number, 0, 0, 0);
  1556.     end_form();
  1557.     newline_form();
  1558. }
  1559.  
  1560. static void
  1561. write_historical_event(hevt)
  1562. HistEvent *hevt;
  1563. {
  1564.     int i;
  1565.     char *descs;
  1566.  
  1567.     start_form(key(K_EVT));
  1568.     add_num_to_form(hevt->startdate);
  1569.     add_to_form(hevtdefns[hevt->type].name);
  1570.     add_num_to_form(hevt->observers);
  1571.     descs = hevtdefns[hevt->type].datadescs;
  1572.     for (i = 0; descs[i] != '\0'; ++i) {
  1573.     switch (descs[i]) {
  1574.       case 'm':
  1575.       case 'n':
  1576.       case 'S':
  1577.       case 'u':
  1578.       case 'U':
  1579.       case 'x':
  1580.       case 'y':
  1581.         add_num_to_form(hevt->data[i]);
  1582.         break;
  1583.       default:
  1584.         run_warning("'%c' is not a recognized data desc char", descs[i]);
  1585.         break;
  1586.     }
  1587.     }
  1588.     end_form();
  1589.     newline_form();
  1590. }
  1591.  
  1592. /* This is a generalized routine to do run-length-encoding of area layers.
  1593.    It uses hook fns to acquire data at a point and an optional translator to
  1594.    do any last-minute fixing.  It can use either a char or numeric encoding,
  1595.    depending on the expected range of values. */
  1596.  
  1597. static void
  1598. write_rle(datafn, lo, hi, translator, compress)
  1599. int (*datafn) PROTO ((int, int)), lo, hi, (*translator) PROTO ((int)), compress;
  1600. {
  1601.     int width, height, x, y, x0, y0, run, runval, val, trval;
  1602.     int numbad = 0;
  1603.  
  1604.     width = area.width;  height = area.height;
  1605.     if (doreshape) {
  1606.     width = reshaper->finalwidth;  height = reshaper->finalheight;
  1607.     }
  1608.     for (y = height-1; y >= 0; --y) {
  1609.     fprintf(fp, "  \"");
  1610.     run = 0;
  1611.     x0 = 0;  y0 = y;
  1612.     if (doreshape)
  1613.       original_point(0, y, &x0, &y0);
  1614.     val = (*datafn)(x0, y0);
  1615.     /* Zero out anything not in the world, unless reshaping. */
  1616.     if (!doreshape && !in_area(x0, y0))
  1617.       val = 0;
  1618.     /* Check that the data falls within bounds, clip if not. */
  1619.     if (lo <= hi && !between(lo, val, hi) && in_area(x0, y0)) {
  1620.         ++numbad;
  1621.         if (val < lo)
  1622.           val = lo;
  1623.         if (val > hi)
  1624.           val = hi;
  1625.     }
  1626.     runval = val;
  1627.     for (x = 0; x < width; ++x) {
  1628.         x0 = x;  y0 = y;
  1629.         if (doreshape)
  1630.           original_point(x, y, &x0, &y0);
  1631.         val = (*datafn)(x0, y0);
  1632.         /* Zero out anything not in the world, unless reshaping. */
  1633.         if (!doreshape && !in_area(x0, y0))
  1634.           val = 0;
  1635.         /* Check that the data falls within bounds, clip if not. */
  1636.         if (lo <= hi && !between(lo, val, hi) && in_area(x0, y0)) {
  1637.         ++numbad;
  1638.         if (val < lo)
  1639.           val = lo;
  1640.         if (val > hi)
  1641.           val = hi;
  1642.         }
  1643.         if (val == runval && compress) {
  1644.         run++;
  1645.         } else {
  1646.         trval = (translator != NULL ? (*translator)(runval) : runval);
  1647.         write_run(run, trval);
  1648.         /* Start a new run. */
  1649.         runval = val;
  1650.         run = 1;
  1651.         }
  1652.     }
  1653.     /* Finish off the row. */
  1654.     trval = (translator != NULL ? (*translator)(val) : val);
  1655.     write_run(run, trval);
  1656.     fprintf(fp, "\"\n");
  1657.     }
  1658.     if (numbad > 0) {
  1659.     run_warning("%d values not between %d and %d", numbad, lo, hi);
  1660.     }
  1661. }
  1662.  
  1663. /* Write a single run, using the most compact encoding possible.
  1664.    0 - 29 is 'a' - '~', 30 - 63 is ':' - '[' */ 
  1665.  
  1666. static void
  1667. write_run(run, val)
  1668. int run, val;
  1669. {
  1670.     if (run > 1) {
  1671.     fprintf(fp, "%d", run);
  1672.     if (val > 63)
  1673.       fprintf(fp, "*");
  1674.     }
  1675.     if (between(0, val, 29)) {
  1676.     fprintf(fp, "%c", val + 'a');
  1677.     } else if (between(30, val, 63)) {
  1678.     fprintf(fp, "%c", val - 30 + ':');
  1679.     } else {
  1680.     fprintf(fp, "%d,", val);
  1681.     }
  1682. }
  1683.  
  1684. /* Compute and return the corresponding point in an area being reshaped. */
  1685.  
  1686. static int
  1687. reshaped_point(x1, y1, x2p, y2p)
  1688. int x1, y1, *x2p, *y2p;
  1689. {
  1690.     *x2p = (((x1 - reshaper->subareax) * reshaper->finalsubareawidth )
  1691.         / reshaper->subareawidth ) + reshaper->finalsubareax;
  1692.     *y2p = (((y1 - reshaper->subareay) * reshaper->finalsubareaheight)
  1693.         / reshaper->subareaheight) + reshaper->finalsubareay;
  1694.     return TRUE;
  1695. }
  1696.  
  1697. static int
  1698. original_point(x1, y1, x2p, y2p)
  1699. int x1, y1, *x2p, *y2p;
  1700. {
  1701.     *x2p = (((x1 - reshaper->finalsubareax) * reshaper->subareawidth )
  1702.         / reshaper->finalsubareawidth ) + reshaper->subareax;
  1703.     *y2p = (((y1 - reshaper->finalsubareay) * reshaper->subareaheight)
  1704.         / reshaper->finalsubareaheight) + reshaper->subareay;
  1705.     return inside_area(*x2p, *y2p);
  1706. }
  1707.  
  1708.